#ifndef ADVCOMREFCOUNTED_H__MINCOM__LOKI__INCLUDED_
#define ADVCOMREFCOUNTED_H__MINCOM__LOKI__INCLUDED_

// Loki::SmartPtr extension 
//////////////////////////////////////////////////////////////////////////

namespace Loki
{

	template < class P >
	class AdvCOMRefCounted
	{
	public:

		AdvCOMRefCounted() 
			: pStrongCount_(MinCOM::Counter::Create())
			, pWeakCount_(MinCOM::Counter::Create())
			, strong_(-1)
		{
		}

		AdvCOMRefCounted(const AdvCOMRefCounted& rhs) 
			: pStrongCount_(rhs.pStrongCount_)
			, pWeakCount_(rhs.pWeakCount_)
			, strong_(-1)
		{}

		template <typename P1>
		AdvCOMRefCounted(const AdvCOMRefCounted<P1>& rhs) 
			: pStrongCount_(reinterpret_cast<const AdvCOMRefCounted&>(rhs).pStrongCount_)
			, pWeakCount_(reinterpret_cast<const AdvCOMRefCounted&>(rhs).pWeakCount_)
			, strong_(-1)
		{}

		~AdvCOMRefCounted()
		{
			if ( ( pStrongCount_ && pWeakCount_ ) &&
				( !pStrongCount_->GetCount() && !pWeakCount_->GetCount() ) )
			{
				MinCOM::Counter::Release(pStrongCount_);
				MinCOM::Counter::Release(pWeakCount_);
			}
		}

		P Clone(const P& val)
		{
			if ( strong_ == -1 )
				return val;

			if ( !val )
				return NULL;

			if ( strong_ == 1 && pStrongCount_ && pStrongCount_->GetCount() == 0 )
				return NULL;

			IncrementCounters();

			if (strong_ != -1 && strong_ && val != 0)
				val->AddRef();

			return val;
		}

		bool Release(const P& val)
		{
			if ( val )
				DecrementCounters();

			if ( ( pStrongCount_ && pWeakCount_ ) &&
				( !pStrongCount_->GetCount() && !pWeakCount_->GetCount() ) )
			{
				MinCOM::Counter::Release(pStrongCount_);
				MinCOM::Counter::Release(pWeakCount_);

				pStrongCount_ = NULL;
				pWeakCount_ = NULL;
			}

			if ( strong_ != -1 && strong_ && val != 0 )
				val->Release();

			return false;
		}

		void Swap(AdvCOMRefCounted& rhs)
		{ 
			std::swap(pStrongCount_, rhs.pStrongCount_); 
			std::swap(pWeakCount_, rhs.pWeakCount_); 
		}

		enum { destructiveCopy = false };

		// Additional support for weak pointers' tuning
		//////////////////////////////////////////////////////////////////////////
		void SetStrong(bool strong)
		{
			strong_ = strong;
		}

		bool CanReturnStrong() const
		{
			return ( pStrongCount_ && pStrongCount_->GetCount() > 0 );
		}

		void SetupNew(bool strong)
		{
			strong_ = strong;

			IncrementCounters();
		}

		void IncrementCounters()
		{
			if ( strong_ )
			{
				if ( pStrongCount_ )
					pStrongCount_->Increment();
			}
			else 
			{
				if ( pWeakCount_ )
					pWeakCount_->Increment();
			}
		}

		void DecrementCounters()
		{
			if ( strong_ )
			{
				if ( pStrongCount_ )
					pStrongCount_->Decrement();
			}
			else 
			{
				if ( pWeakCount_ )
					pWeakCount_->Decrement();
			}
		}

		template <typename P1>
		void UpdateExistentCounters(const AdvCOMRefCounted<P1>& rhs)
		{
			if ( pStrongCount_ && pWeakCount_ )
			{
				MinCOM::Counter::Release(pStrongCount_);
				MinCOM::Counter::Release(pWeakCount_);
			}

			pStrongCount_ = reinterpret_cast<const AdvCOMRefCounted&>(rhs).pStrongCount_;
			pWeakCount_ = reinterpret_cast<const AdvCOMRefCounted&>(rhs).pWeakCount_;
		}

		void UpdateExistentCounters(const AdvCOMRefCounted& rhs)
		{
			if ( pStrongCount_ && pWeakCount_ )
			{
				MinCOM::Counter::Release(pStrongCount_);
				MinCOM::Counter::Release(pWeakCount_);
			}

			pStrongCount_ = rhs.pStrongCount_;
			pWeakCount_ = rhs.pWeakCount_;
		}

		/*void UpdateExistentCounters(uintptr_t* pStrongCount, uintptr_t* pWeakCount)
		{
			if ( pStrongCount_ && pWeakCount_ )
			{
				pStrongCount_->Release();
				pWeakCount_->Release();
			}

			pStrongCount_ = pStrongCount;
			pWeakCount_ = pWeakCount;
		}*/

	protected:

		// Counters
		MinCOM::Counter* pStrongCount_;

		MinCOM::Counter* pWeakCount_;

	private:

		int strong_;

	};

}

#endif // !ADVCOMREFCOUNTED_H__MINCOM__LOKI__INCLUDED_
